// i.r(t), i.d(t, { Sdk: () => Sdk, default: () => L })

import Module from "./Module"
import EventEmitter from "eventemitter3"

var n = {
  POSTMESSAGE: "postmessage",
  DIRECT: "direct"
}
var r = {
  COLL_UPDATED: "collection.coll.updated",
  ITEM_ADDED: "collection.item.added",
  ITEM_REMOVED: "collection.item.removed",
  ITEM_UPDATED: "collection.item.updated"
}

var a = {
  Event: {
    MOVE: "camera.move"
  },
  Direction: {
    FORWARD: "FORWARD",
    LEFT: "LEFT",
    RIGHT: "RIGHT",
    BACK: "BACK",
    UP: "UP",
    DOWN: "DOWN"
  }
}
var l = {
  Event: {
    CHANGE_START: "floors.changestart",
    CHANGE_END: "floors.changeend"
  }
}
var c = {
  Event: {
    POSITION_UPDATED: "label.positionupdated"
  }
}
var h = {
  Transition: {
    INSTANT: "transition.instant",
    FLY: "transition.fly",
    FADEOUT: "transition.fade"
  },
  LinkType: {
    NAVIGATION: "tag.link.nav",
    MODEL: "tag.link.model",
    EXT_LINK: "tag.link.ext"
  },
  DescriptionChunkType: {
    NONE: "tag.chunk.none",
    TEXT: "tag.chunk.text",
    LINK: "tag.chunk.link"
  },
  Event: {
    HOVER: "tag.hover",
    CLICK: "tag.click",
    LINK_OPEN: "tag.linkopen"
  },
  MediaType: {
    NONE: "mattertag.media.none",
    PHOTO: "mattertag.media.photo",
    VIDEO: "mattertag.media.video",
    RICH: "mattertag.media.rich"
  }
}
var s = {
  EVENT: "postmessage.event",
  RESPONSE: "postmessage.response",
  OBSERVATION: "postmessage.observation",
  COLLECTION_UPDATE: "collection.updated"
}
var d = {
  Mode: {
    INSIDE: "mode.inside",
    OUTSIDE: "mode.outside",
    DOLLHOUSE: "mode.dollhouse",
    FLOORPLAN: "mode.floorplan",
    TRANSITIONING: "mode.transitioning"
  },
  Event: {
    CHANGE_START: "viewmode.changestart",
    CHANGE_END: "viewmode.changeend"
  },
  TransitionType: {
    INSTANT: "transition.instant",
    FLY: "transition.fly",
    FADEOUT: "transition.fade"
  }
}
var u = {
  Event: {
    MODEL_LOADED: "model.loaded"
  }
}
var p = {
  Colliders: {
    NONE: "intersectedobject.none",
    MODEL: "intersectedobject.model",
    TAG: "intersectedobject.tag",
    SWEEP: "intersectedobject.sweep",
    UNKNOWN: "intersectedobject.unknown"
  }
}
var m = {
  InteractionType: {
    CLICK: "INTERACTION.CLICK",
    HOVER: "INTERACTION.HOVER",
    DRAG: "INTERACTION.DRAG",
    DRAG_BEGIN: "INTERACTION.DRAG_BEGIN",
    DRAG_END: "INTERACTION.DRAG_END",
    POINTER_MOVE: "INTERACTION.POINTER_MOVE",
    POINTER_BUTTON: "INTERACTION.POINTER_BUTTON",
    SCROLL: "INTERACTION.SCROLL",
    KEY: "INTERACTION.KEY",
    LONG_PRESS_START: "INTERACTION.LONG_PRESS_START",
    LONG_PRESS_END: "INTERACTION.LONG_PRESS_END",
    MULTI_SWIPE: "INTERACTION.MULTI_SWIPE",
    MULTI_SWIPE_END: "INTERACTION.MULTI_SWIPE_END",
    PINCH: "INTERACTION.PINCH",
    PINCH_END: "INTERACTION.PINCH_END",
    ROTATE: "INTERACTION.ROTATE",
    ROTATE_END: "INTERACTION.ROTATE_END"
  },
  PathType: {
    INPUT: "input",
    OUTPUT: "output",
    EVENT: "event",
    EMIT: "emit"
  }
}
var g = {
  SensorType: {
    CAMERA: "sensor.sensortype.camera"
  },
  SourceType: {
    SPHERE: "sensor.sourcetype.sphere",
    BOX: "sensor.sourcetype.box",
    CYLINDER: "sensor.sourcetype.cylinder"
  }
}
var f = {
  Event: {
    ENTER: "sweep.enter",
    EXIT: "sweep.exit"
  },
  Transition: {
    INSTANT: "transition.instant",
    FLY: "transition.fly",
    FADEOUT: "transition.fade"
  },
  Alignment: {
    ALIGNED: "aligned",
    UNALIGNED: "unaligned"
  },
  Placement: {
    UNPLACED: "unplaced",
    AUTO: "auto",
    MANUAL: "manual"
  }
}
var v = {
  Event: {
    STARTED: "tour.started",
    STOPPED: "tour.stopped",
    ENDED: "tour.ended",
    STEPPED: "tour.stepped"
  }
}
var S = {
  ACTION: "postmessage.action",
  COLLECTION_SUB: "collection.sub",
  COLLECTION_UNSUB: "collection.unsub",
  DISCONNECT: "sdk.client.disconnect",
  EVENT_SUB: "postmessage.subscribe",
  EVENT_UNSUB: "postmessage.unsubscribe",
  OBSERVABLE_SUB: "postmessage.observe",
  OBSERVABLE_UNSUB: "postmessage.unobserve"
}

var E = {
  map: new Map()
}

var T = {
  ACCEPT: "postmessage.accept",
  ACTION: "postmessage.action",
  CONNECT: "postmessage.connect",
  DISCONNECT: "postmessage.disconnect",
  EVENT: "postmessage.event",
  EVENT_SUB: "postmessage.subscribe",
  EVENT_UNSUB: "postmessage.unsubscribe",
  HANDSHAKE: "postmessage.handshake",
  OBSERVABLE_SUB: "postmessage.observe",
  OBSERVABLE_UNSUB: "postmessage.unobserve",
  OBSERVABLE_UPDATE: "postmessage.observation",
  REJECT: "postmessage.reject",
  RESPONSE: "postmessage.response"
}

class PostMessage extends EventEmitter {
  id: any
  clientId: any
  clientWindow: any
  clientOrigin: any
  hostWindow: any
  messageHandler: (e: any) => void
  constructor(e, t, i) {
    super(),
      (this.id = t),
      (this.clientId = i),
      (this.clientWindow = null),
      (this.clientOrigin = null),
      (this.hostWindow = e),
      (this.messageHandler = e => {
        this.onPostmessageReceived(e)
      }),
      this.bindEvents()
  }
  send(e) {
    this.clientWindow &&
      this.clientOrigin &&
      this.clientWindow.postMessage(
        Object.assign(Object.assign({ payload: e }, e), {
          fromId: this.id
        }),
        this.clientOrigin
      )
  }
  setTarget(e, t) {
    ;(this.clientWindow = e), (this.clientOrigin = t)
  }
  clearTarget() {
    ;(this.clientWindow = null), (this.clientOrigin = null)
  }
  bindEvents() {
    this.hostWindow.addEventListener("message", this.messageHandler)
  }
  dispose() {
    this.hostWindow.removeEventListener("message", this.messageHandler)
  }
  onPostmessageReceived(e) {
    const t = e.origin,
      i = e.source
    if (i) {
      switch (e.data.type) {
        case T.CONNECT:
          break
        case T.DISCONNECT:
        case T.ACTION:
        case T.EVENT_SUB:
        case T.EVENT_UNSUB:
        case T.OBSERVABLE_SUB:
        case T.OBSERVABLE_UNSUB:
        case S.COLLECTION_SUB:
        case S.COLLECTION_UNSUB:
          if (!this.validateMessageOrigin(e.data.fromId, t, i)) return
          break
        default:
          return
      }
      if (e.data.payload)
        this.emit(
          e.data.type,
          Object.assign(Object.assign({}, e.data.payload), {
            type: e.data.type,
            fromId: e.data.fromId,
            source: i,
            origin: t,
            method: n.POSTMESSAGE
          })
        )
      else {
        const s = Object.assign(Object.assign({}, e.data), {
          source: i,
          origin: t,
          timestamp: Date.now(),
          method: n.POSTMESSAGE
        })
        this.emit(e.data.type, s)
      }
    }
  }
  validateMessageOrigin(e, t, i) {
    return (-1 === this.clientId && "*" === this.clientOrigin) || (this.clientId === e && this.clientWindow === i && this.clientOrigin === t)
  }
}
var w = {
  CONNECTION: "sdk.connection",
  DISCONNECT: "sdk.disconnect",
  MESSAGED: "sdk.messaged",
  SUBSCRIBED: "sdk.subscribed",
  UNSUBSCRIBED: "sdk.unsubscribed",
  OBSERVABLE_SUB: "sdk.obs.subscribe",
  OBSERVABLE_UNSUB: "sdk.obs.unsubscribe",
  COLLECTION_SUB: "sdk.coll.subscribe",
  COLLECTION_UNSUB: "sdk.coll.unsubscribe"
}

import Logger from "../utils/Logger"
const M = new Logger("SdkHost")
class PostMessageHost extends EventEmitter {
  hostWindow: any
  id: any
  clients: {}
  connectionHandler: PostMessage
  constructor(e, t) {
    super(), (this.hostWindow = e), (this.id = t), (this.clients = {}), (this.connectionHandler = new PostMessage(e, this.id, -1)), this.bindEvents(e)
  }
  broadcastEventToClient(e, t, i) {
    const n = this.clients[e]
    if (!n) return
    const s = { type: T.EVENT, eventType: t, eventData: i, toId: e }
    n.messenger.send(s)
  }
  broadcastObservationToClient(e, t, i) {
    const n = this.clients[e]
    if (!n) return
    const s = {
      type: T.OBSERVABLE_UPDATE,
      observableKey: t,
      observableData: i,
      toId: e
    }
    n.messenger.send(s)
  }
  broadcastCollectionItemAdded(e, t, i, n) {
    const o = this.clients[e]
    if (!o) return
    const a = {
      type: s.COLLECTION_UPDATE,
      operation: r.ITEM_ADDED,
      collectionKey: t,
      collectionIndex: i,
      item: n,
      toId: e
    }
    o.messenger.send(a)
  }
  broadcastCollectionItemRemoved(e, t, i) {
    const n = this.clients[e]
    if (!n) return
    const o = {
      type: s.COLLECTION_UPDATE,
      operation: r.ITEM_REMOVED,
      collectionKey: t,
      collectionIndex: i,
      toId: e
    }
    n.messenger.send(o)
  }
  broadcastCollectionItemUpdated(e, t, i, n) {
    const o = this.clients[e]
    if (!o) return
    const a = {
      type: s.COLLECTION_UPDATE,
      operation: r.ITEM_UPDATED,
      collectionKey: t,
      collectionIndex: i,
      item: n,
      toId: e
    }
    o.messenger.send(a)
  }
  broadcastCollectionUpdated(e, t) {
    const i = this.clients[e]
    if (!i) return
    const n = {
      type: s.COLLECTION_UPDATE,
      operation: r.COLL_UPDATED,
      collectionKey: t,
      toId: e
    }
    i.messenger.send(n)
  }
  broadcastEvent(e, t, i = !0) {
    for (const n of Object.keys(this.clients)) (i || this.clients[parseInt(n, 10)].subscriptions[e]) && this.broadcastEventToClient(parseInt(n, 10), e, t)
  }
  bindEvents(e) {
    this.connectionHandler.on(T.CONNECT, t => {
      const i = new PostMessage(e, this.id, t.fromId)
      this.onConnectionReceived(i, t)
    })
  }
  onConnectionReceived(e, t) {
    const i = Object.assign(Object.assign({}, t), {
      handshake: () => {
        const n = this.clients[i.fromId]
        if (n && n.connected) return void M.info(`client already connected: ${i.fromId}`)
        this.clients[i.fromId] = {
          origin: t.origin,
          messenger: e,
          subscriptions: {},
          connected: !1
        }
        const s = { type: T.HANDSHAKE, toId: i.fromId }
        M.info(`handshake ${i.fromId}`), e.send(s)
      },
      accept: (t, n, s) => {
        const r = this.clients[i.fromId]
        if (r && r.connected) return void M.info(`client already connected: ${i.fromId}`)
        const o = {
          type: T.ACCEPT,
          toId: i.fromId,
          targetId: this.id,
          targetOrigin: `${this.hostWindow.location.protocol}//${this.hostWindow.location.host}`,
          warning: s,
          scriptUrl: t,
          interface: n
        }
        M.info(`accept ${i.fromId}`),
          e.send(o),
          (r.connected = !0),
          e.on(T.DISCONNECT, e => this.onDisconnectReceived(r, e)),
          e.on(T.ACTION, e => this.onMessageReceived(r, e)),
          e.on(T.EVENT_SUB, e => this.onEventSubscribe(r, e)),
          e.on(T.EVENT_UNSUB, e => this.onEventUnsubscribe(r, e)),
          e.on(T.OBSERVABLE_SUB, e => this.onObservableSubscribe(r, e)),
          e.on(T.OBSERVABLE_UNSUB, e => this.onObservableUnsubscribe(r, e)),
          e.on(S.COLLECTION_SUB, e => this.onCollectionSubscribe(r, e)),
          e.on(S.COLLECTION_UNSUB, e => this.onCollectionUnsubscribe(r, e))
      },
      reject: t => {
        const n = { type: T.REJECT, toId: i.fromId, reason: t }
        e.send(n), e.clearTarget(), e.dispose(), delete this.clients[i.fromId]
      },
      method: n.POSTMESSAGE
    })
    e.setTarget(i.source, i.origin), this.emit(w.CONNECTION, i)
  }
  onDisconnectReceived(e, t) {
    delete this.clients[t.fromId], this.emit(w.DISCONNECT, e, t)
  }
  onMessageReceived(e, t) {
    const i: any = {
      toId: t.fromId,
      uid: t.uid,
      message: null,
      success: !0,
      type: T.RESPONSE,
      timestamp: Date.now()
    }
    function n(t) {
      ;(i.message = t), e.messenger.send(i)
    }
    const s = Object.assign(Object.assign({}, t), {
      origin: e.origin,
      onSuccess: e => {
        n(e)
      },
      onFail: e => {
        i.success = !1
        i.error = e
        n(e)
      }
    })
    this.emit(w.MESSAGED, s)
  }
  onEventSubscribe(e, t) {
    ;(e.subscriptions[t.subscription] = !0), this.emitSdkEvent(w.SUBSCRIBED, e, t)
  }
  onEventUnsubscribe(e, t) {
    ;(e.subscriptions[t.subscription] = !1), this.emitSdkEvent(w.UNSUBSCRIBED, e, t)
  }
  onObservableSubscribe(e, t) {
    this.emitSdkEvent(w.OBSERVABLE_SUB, e, t)
  }
  onObservableUnsubscribe(e, t) {
    this.emitSdkEvent(w.OBSERVABLE_UNSUB, e, t)
  }
  onCollectionSubscribe(e, t) {
    this.emitSdkEvent(w.COLLECTION_SUB, e, t)
  }
  onCollectionUnsubscribe(e, t) {
    this.emitSdkEvent(w.COLLECTION_UNSUB, e, t)
  }
  emitSdkEvent(e, t, i) {
    this.emit(e, Object.assign(Object.assign({}, i), { origin: t.origin }))
  }
}
import { DirectMessageBridge, DirectMessageFactory, DirectMessageNode, Messenger } from "../sdk/MessageBridge"
export class ConnectionObserverAdaptor {
  observer: DirectMessageHostFacade
  origin: any
  constructor(e: DirectMessageHostFacade, t) {
    this.observer = e
    this.origin = t
  }
  notify(e: number, t: DirectMessageNode, i: Messenger) {
    this.observer.onConnectionReceived(this.origin, {
      id: e,
      node: t,
      messenger: i
    })
  }
}
class FunctionCallMessageObserver {
  receiver: any
  clientId: any
  messageType: string
  constructor(e, t) {
    this.receiver = e
    this.clientId = t
    this.messageType = S.ACTION
  }
  notify(e) {
    this.receiver.receiveAction(e, this.clientId)
  }
}
class EventSubscribeMessageObserver {
  observer: any
  clientId: any
  messageType: string
  constructor(e, t) {
    ;(this.observer = e), (this.clientId = t), (this.messageType = S.EVENT_SUB)
  }
  notify(e) {
    this.observer.receiveEventSub(e, this.clientId)
  }
}
class EventUnsubscribeMessageObserver {
  observer: any
  clientId: any
  messageType: string
  constructor(e, t) {
    ;(this.observer = e), (this.clientId = t), (this.messageType = S.EVENT_UNSUB)
  }
  notify(e) {
    this.observer.receiveEventUnsub(e, this.clientId)
  }
}
class ObservableSubMessageObserver {
  observer: any
  clientId: any
  messageType: string
  constructor(e, t) {
    ;(this.observer = e), (this.clientId = t), (this.messageType = S.OBSERVABLE_SUB)
  }
  notify(e) {
    this.observer.receiveObservableSub(e, this.clientId)
  }
}
class ObservableUnsubMessageObserver {
  observer: any
  clientId: any
  messageType: string
  constructor(e, t) {
    ;(this.observer = e), (this.clientId = t), (this.messageType = S.OBSERVABLE_UNSUB)
  }
  notify(e) {
    this.observer.receiveObservableUnsub(e, this.clientId)
  }
}
class CollectionSubMessageObserver {
  observer: any
  clientId: any
  messageType: string
  constructor(e, t) {
    ;(this.observer = e), (this.clientId = t), (this.messageType = S.COLLECTION_SUB)
  }
  notify(e) {
    this.observer.receiveCollectionSub(e, this.clientId)
  }
}
class CollectionUnsubMessageObserver {
  observer: any
  clientId: any
  messageType: string
  constructor(e, t) {
    ;(this.observer = e), (this.clientId = t), (this.messageType = S.COLLECTION_UNSUB)
  }
  notify(e) {
    this.observer.receiveCollectionUnsub(e, this.clientId)
  }
}
class ResponseMessage {
  type: any
  payload: { uid: any; message: any; success: any; error: any }
  constructor(e, t, i, n) {
    ;(this.type = s.RESPONSE), (this.payload = { uid: e, message: t, success: i, error: n })
  }
}
class EventMessage {
  type: any
  payload: { eventType: any; eventData: any }
  constructor(e, t) {
    ;(this.type = s.EVENT), (this.payload = { eventType: e, eventData: t })
  }
}
class ObservationMessage {
  type: any
  payload: { observableKey: any; observableData: any }
  constructor(e, t) {
    ;(this.type = s.OBSERVATION), (this.payload = { observableKey: e, observableData: t })
  }
}
class CollectionItemAddedMessage {
  type: any
  payload: { operation: any; collectionKey: any; collectionIndex: any; item: any }
  constructor(e, t, i, n) {
    ;(this.type = s.COLLECTION_UPDATE),
      (this.payload = {
        operation: e,
        collectionKey: t,
        collectionIndex: i,
        item: n
      })
  }
}
class CollectionItemRemovedMessage {
  type: any
  payload: { operation: any; collectionKey: any; collectionIndex: any }
  constructor(e, t, i) {
    ;(this.type = s.COLLECTION_UPDATE),
      (this.payload = {
        operation: e,
        collectionKey: t,
        collectionIndex: i
      })
  }
}
class CollectionItemUpdatedMessage {
  type: any
  payload: { operation: any; collectionKey: any; collectionIndex: any; item: any }
  constructor(e, t, i, n) {
    ;(this.type = s.COLLECTION_UPDATE),
      (this.payload = {
        operation: e,
        collectionKey: t,
        collectionIndex: i,
        item: n
      })
  }
}
class CollectionUpdatedMessage {
  type: any
  payload: { operation: any; collectionKey: any }
  constructor(e, t) {
    ;(this.type = s.COLLECTION_UPDATE), (this.payload = { operation: e, collectionKey: t })
  }
}
class DirectMessageHost {
  hostId: number
  host: DirectMessageNode
  clientConnections: {}
  clientEventSubscriptions: DictArray
  clientObservableSubscriptions: DictArray
  clientCollectionSubscriptions: DictArray
  facade: DirectMessageHostFacade
  static DirectMessageHostFacade: typeof DirectMessageHostFacade
  disconnectCallback: any
  functionCallcallback: any
  eventSubCallback: any
  eventUnsubCallback: any
  observableSubCallback: any
  observableUnsubCallback: any
  collectionSubCallback: any
  collectionUnsubCallback: any
  constructor(e) {
    this.hostId = e
    this.host = new DirectMessageNode()
    this.clientConnections = {}
    this.clientEventSubscriptions = new DictArray()
    this.clientObservableSubscriptions = new DictArray()
    this.clientCollectionSubscriptions = new DictArray()
    this.facade = new DirectMessageHost.DirectMessageHostFacade(this)
  }
  createFactory(e) {
    const t = new ConnectionObserverAdaptor(this.facade, e)
    return new DirectMessageFactory(this.hostId, this.host, t)
  }
  broadcastEvent(e, t, i = !0) {
    const n = this.clientEventSubscriptions.getValuesAtKey(e)
    if (n || i) for (const i of n) this.clientConnections[i].hostToClient.send(new EventMessage(e, t || []))
  }
  broadcastObservationToClient(e, t) {
    const i = this.clientObservableSubscriptions.getValuesAtKey(e)
    if (i) for (const n of i) this.clientConnections[n].hostToClient.send(new ObservationMessage(e, t))
  }
  broadcastCollectionItemAdded(e, t, i) {
    const n = this.clientCollectionSubscriptions.getValuesAtKey(e)
    if (n) for (const s of n) this.clientConnections[s].hostToClient.send(new CollectionItemAddedMessage(r.ITEM_ADDED, e, t, i))
  }
  broadcastCollectionItemRemoved(e, t) {
    const i = this.clientCollectionSubscriptions.getValuesAtKey(e)
    if (i) for (const n of i) this.clientConnections[n].hostToClient.send(new CollectionItemRemovedMessage(r.ITEM_REMOVED, e, t))
  }
  broadcastCollectionItemUpdated(e, t, i) {
    const n = this.clientCollectionSubscriptions.getValuesAtKey(e)
    if (n) for (const s of n) this.clientConnections[s].hostToClient.send(new CollectionItemUpdatedMessage(r.ITEM_UPDATED, e, t, i))
  }
  broadcastCollectionUpdated(e) {
    const t = this.clientCollectionSubscriptions.getValuesAtKey(e)
    if (t) for (const i of t) this.clientConnections[i].hostToClient.send(new CollectionUpdatedMessage(r.COLL_UPDATED, e))
  }
  onDisconnectReceived(e) {
    this.disconnectCallback = e
  }
  onCallReceived(e) {
    this.functionCallcallback = e
  }
  onSubscribeReceived(e) {
    this.eventSubCallback = e
  }
  onUnsubscribeReceived(e) {
    this.eventUnsubCallback = e
  }
  onObservableSubReceived(e) {
    this.observableSubCallback = e
  }
  onObservableUnsubReceived(e) {
    this.observableUnsubCallback = e
  }
  onCollectionSubReceived(e) {
    this.collectionSubCallback = e
  }
  onCollectionUnsubReceived(e) {
    this.collectionUnsubCallback = e
  }
  createHostToClientConnection(e, t) {
    const i = new Messenger(this.hostId, e, new DirectMessageBridge(this.host, t)),
      n = new DirectMessageHost.DirectMessageHostFacade(this)
    return (
      i.addObserver(new FunctionCallMessageObserver(n, e)),
      i.addObserver(new EventSubscribeMessageObserver(n, e)),
      i.addObserver(new EventUnsubscribeMessageObserver(n, e)),
      i.addObserver(new ObservableSubMessageObserver(n, e)),
      i.addObserver(new ObservableUnsubMessageObserver(n, e)),
      i.addObserver(new CollectionSubMessageObserver(n, e)),
      i.addObserver(new CollectionUnsubMessageObserver(n, e)),
      i.init(),
      i
    )
  }
  onConnectionReceived(e, t) {
    const i = t.id
    const n = this.createHostToClientConnection(i, t.node)
    this.clientConnections[i] = {
      id: i,
      clientToHost: t.messenger,
      hostToClient: n,
      origin: e
    }
  }
  disconnect(e, t) {
    const i = this.clientConnections[t]
    i &&
      (delete this.clientConnections[t],
      this.disconnectCallback &&
        this.disconnectCallback(
          Object.assign(Object.assign({}, e), {
            type: T.DISCONNECT,
            uid: -1,
            fromId: t,
            origin: i.origin,
            method: n.DIRECT,
            source: void 0
          })
        ))
  }
  receiveAction(e, t) {
    const i = this.clientConnections[t]
    if (!i) return
    const s = t => {
        i.hostToClient.send(new ResponseMessage(e.uid, t, !0, ""))
      },
      r = t => {
        i.hostToClient.send(new ResponseMessage(e.uid, {}, !1, t))
      }
    this.functionCallcallback &&
      this.functionCallcallback(
        Object.assign(Object.assign({}, e), {
          type: T.ACTION,
          onSuccess: s,
          onFail: r,
          fromId: t,
          origin: i.origin,
          method: n.DIRECT,
          source: void 0
        })
      )
  }
  receiveEventSub(e, t) {
    const i = this.clientConnections[t]
    i && this.eventSubCallback && (this.clientEventSubscriptions.add(e.subscription, t), this.eventSubCallback(this.createBridgedMessage(T.EVENT_SUB, e, i)))
  }
  receiveEventUnsub(e, t) {
    const i = this.clientConnections[t]
    i &&
      this.eventUnsubCallback &&
      (this.clientEventSubscriptions.remove(e.subscription, t), this.eventUnsubCallback(this.createBridgedMessage(T.EVENT_UNSUB, e, i)))
  }
  receiveObservableSub(e, t) {
    const i = this.clientConnections[t]
    i &&
      this.observableSubCallback &&
      (this.clientObservableSubscriptions.add(e.observableKey, t), this.observableSubCallback(this.createBridgedMessage(T.OBSERVABLE_SUB, e, i)))
  }
  receiveObservableUnsub(e, t) {
    const i = this.clientConnections[t]
    i &&
      this.observableUnsubCallback &&
      (this.clientObservableSubscriptions.remove(e.observableKey, t), this.observableUnsubCallback(this.createBridgedMessage(T.OBSERVABLE_UNSUB, e, i)))
  }
  receiveCollectionSub(e, t) {
    const i = this.clientConnections[t]
    i &&
      this.collectionSubCallback &&
      (this.clientCollectionSubscriptions.add(e.collectionKey, t), this.collectionSubCallback(this.createBridgedMessage(S.COLLECTION_SUB, e, i)))
  }
  receiveCollectionUnsub(e, t) {
    const i = this.clientConnections[t]
    i &&
      this.collectionUnsubCallback &&
      (this.clientCollectionSubscriptions.remove(e.collectionKey, t), this.collectionUnsubCallback(this.createBridgedMessage(S.COLLECTION_UNSUB, e, i)))
  }
  createBridgedMessage(e, t, i) {
    return Object.assign(Object.assign({}, t), {
      fromId: i.id,
      uid: -1,
      type: e,
      origin: i.origin,
      method: n.DIRECT,
      source: void 0
    })
  }
}
class DirectMessageHostFacade {
  directMessageHost: any
  constructor(e) {
    this.directMessageHost = e
  }
  onConnectionReceived(e, t) {
    this.directMessageHost.onConnectionReceived(e, t)
  }
  disconnect(e, t) {
    this.directMessageHost.disconnect(e, t)
  }
  receiveAction(e, t) {
    this.directMessageHost.receiveAction(e, t)
  }
  receiveEventSub(e, t) {
    this.directMessageHost.receiveEventSub(e, t)
  }
  receiveEventUnsub(e, t) {
    this.directMessageHost.receiveEventUnsub(e, t)
  }
  receiveObservableSub(e, t) {
    this.directMessageHost.receiveObservableSub(e, t)
  }
  receiveObservableUnsub(e, t) {
    this.directMessageHost.receiveObservableUnsub(e, t)
  }
  receiveCollectionSub(e, t) {
    this.directMessageHost.receiveCollectionSub(e, t)
  }
  receiveCollectionUnsub(e, t) {
    this.directMessageHost.receiveCollectionUnsub(e, t)
  }
}
DirectMessageHost.DirectMessageHostFacade = DirectMessageHostFacade

import { SdkObserver } from "../observer/observable.sdk"
import SdkData from "../data/SdkData"
import AnalyticsModule from "./AnalyticsModule"
import OpenDeferred from "../utils/OpenDeferred"
import { DictArray } from "../utils/array.util"
import EngineContext from "../EngineContext"
import CommandBinder from "../CommandBinder"
import { RequestQueue } from "../utils/request.util"
var O = {
  EMBED: "sdk.embed",
  BUNDLE: "sdk.bundle"
}

class AnalyticsProxy {
  analytics: AnalyticsModule
  sdkType: string
  trackedEvents: {}
  constructor(e, t: string) {
    this.analytics = e
    this.sdkType = t
    this.trackedEvents = {}
  }
  track(e, t, i) {
    ;(this.trackedEvents[e] && this.trackedEvents[e][t]) ||
      ((this.trackedEvents[e] = this.trackedEvents[e] || {}),
      (this.trackedEvents[e][t] = !0),
      this.analytics.track(e, Object.assign({ sdkType: this.sdkType }, i)))
  }
}
const N = new Logger("sdk")
export default class Sdk extends Module {
  hostId: number
  triedLoadingInterface: boolean
  clientInterface: { functions: {}; commands: {}; enums: {}; observables: {}; collections: {} }
  valueToClientInterface: {}
  commandCreators: {}
  registeredEventUsers: {}
  commands: {}
  observables: {}
  registeredObservers: {}
  collections: {}
  registeredCollectionObservers: {}
  observerMap: Map<any, any>
  config: any
  applicationKey: string
  validationUrl: string
  postMessageHost: PostMessageHost
  directMessageHost: DirectMessageHost
  analytics: AnalyticsProxy
  clientFilter: (e?: any) => boolean
  issueCommand: CommandBinder["issueCommand"]
  interfacePromise: OpenDeferred<any>
  getClientScriptUrl: (e?: any) => Promise<string>
  requestQueue: RequestQueue
  data: SdkData
  constructor() {
    super(...arguments), (this.name = "sdk")
    this.hostId = Math.floor(1000000 * Math.random())
    this.triedLoadingInterface = !1
    this.clientInterface = {
      functions: {},
      commands: {},
      enums: {},
      observables: {},
      collections: {}
    }
    this.valueToClientInterface = {}
    this.commandCreators = {}
    this.registeredEventUsers = {}
    this.commands = {}
    this.observables = {}
    this.registeredObservers = {}
    this.collections = {}
    this.registeredCollectionObservers = {}
    this.observerMap = new Map()
  }
  async init(e, t: EngineContext) {
    this.config = e
    this.applicationKey = e.applicationKey
    this.validationUrl = e.validationUrl
    this.postMessageHost = new PostMessageHost(window, this.hostId)
    this.directMessageHost = new DirectMessageHost(this.hostId)
    this.analytics = new AnalyticsProxy(await t.getModule(AnalyticsModule), O.BUNDLE)
    this.clientFilter = e.clientFilter || (() => !0)
    this.issueCommand = t.commandBinder.issueCommand.bind(t.commandBinder)
    this.interfacePromise = new OpenDeferred()
    this.getClientScriptUrl = e.getClientScriptUrl
    this.requestQueue = e.queue
    this.data = new SdkData()
    t.market.register(this, SdkData, this.data)
    this.enableHandshaking()
  }
  dispose() {
    this.clearInterface()
  }
  async connect(origin: string, options: any) {
    return new Promise((resolve, reject) => {
      this.setupInterface()
      this.onConnectionReceived({
        accept: (scriptUrl, serializedInterface, warning) => {
          resolve({
            targetId: this.hostId,
            targetOrigin: origin,
            scriptUrl,
            serializedInterface,
            messengerFactory: this.directMessageHost.createFactory(origin),
            warning
          })
          this.data.atomic(() => {
            this.data.applicationKey = this.applicationKey
          })
        },
        reject,
        handshake: () => {},
        options,
        origin,
        method: n.DIRECT
      })
    })
  }
  enableHandshaking() {
    this.postMessageHost.once(w.CONNECTION, () => this.setupInterface())
    this.postMessageHost.on(w.CONNECTION, e => this.onConnectionReceived(e))
  }
  async setupInterface() {
    if (!this.triedLoadingInterface)
      try {
        this.triedLoadingInterface = !0
        await this.config.setupExternalSdk(this)
        this.acceptConnections()
      } catch (e) {
        this.interfacePromise.reject(e["message"])
      }
  }
  acceptConnections() {
    this.postMessageHost.on(w.DISCONNECT, e => this.disconnectClient(e))
    this.postMessageHost.on(w.MESSAGED, e => this.onActionReceived(e))
    this.postMessageHost.on(w.SUBSCRIBED, e => this.onSubscribeReceived(e))
    this.postMessageHost.on(w.UNSUBSCRIBED, e => this.onUnsubscribeReceived(e))
    this.postMessageHost.on(w.OBSERVABLE_SUB, e => this.onObservableSubReceived(e))
    this.postMessageHost.on(w.OBSERVABLE_UNSUB, e => this.onObservableUnsubReceived(e))
    this.postMessageHost.on(w.COLLECTION_SUB, e => this.onCollectionSubReceived(e))
    this.postMessageHost.on(w.COLLECTION_UNSUB, e => this.onCollectionUnsubReceived(e))
    this.directMessageHost.onDisconnectReceived(e => this.disconnectClient(e))
    this.directMessageHost.onCallReceived(e => this.onActionReceived(e))
    this.directMessageHost.onSubscribeReceived(e => this.onSubscribeReceived(e))
    this.directMessageHost.onUnsubscribeReceived(e => this.onUnsubscribeReceived(e))
    this.directMessageHost.onObservableSubReceived(e => this.onObservableSubReceived(e))
    this.directMessageHost.onObservableUnsubReceived(e => this.onObservableUnsubReceived(e))
    this.directMessageHost.onCollectionSubReceived(e => this.onCollectionSubReceived(e))
    this.directMessageHost.onCollectionUnsubReceived(e => this.onCollectionUnsubReceived(e))
    this.interfacePromise.resolve()
  }
  clearInterface() {
    this.clientInterface.functions = {}
    this.clientInterface.commands = {}
    this.clientInterface.enums = {}
    this.clientInterface.observables = {}
    this.clientInterface.collections = {}
    this.commandCreators = {}
  }
  onUpdate() {
    if (this.observerMap.size) {
      for (const [e, [t, i, n]] of this.observerMap) {
        if (e.dirty) {
          this.notifyObservableUpdate(t, i, n.getData())
          e.dirty = !1
        }
      }
    }
  }
  addCommandCreator(e: { namespace: string; name: string; args?: string[] }, t: Function) {
    const i = this.getInterfaceIndex(e)
    this.clientInterface.functions.hasOwnProperty(i) && N.debug(`Overwriting ${i} function in sdk interface`)
    this.clientInterface.functions[i] = e
    this.commandCreators[i] = t
  }
  addEnumToInterface(e) {
    const t = this.getInterfaceIndex(e)
    this.clientInterface.functions.hasOwnProperty(t) && N.debug(`Overwriting ${t} enum in sdk interface`)
    this.clientInterface.enums[t] = Object.assign(Object.assign({}, e), {
      values: Object.assign({}, e.values)
    })
    if ("Event" === e.name) {
      const t = Object.keys(e.values)
      for (const i in t) {
        this.valueToClientInterface
        const n = e.values[t[i]]
        this.valueToClientInterface.hasOwnProperty(n) ? N.warn(`Duplicate event detected for ${JSON.stringify(e)}`) : (this.valueToClientInterface[n] = e)
      }
    }
  }
  async addCommandToInterface(e, t) {
    const i = this.getInterfaceIndex(e)
    this.addCommand(i, t), (this.clientInterface.commands[i] = e)
  }
  async addCommand(e, t) {
    this.clientInterface.commands.hasOwnProperty(e), (this.commands[e] = await t)
    const i = this
    return {
      dispose() {
        i.removeCommand(e)
      }
    }
  }
  removeCommand(e) {
    delete this.commands[e]
  }
  addObservableToInterface(e, t) {
    const i = this.getInterfaceIndex(e)
    this.addObservable(i, t), (this.clientInterface.observables[i] = Object.assign({}, e))
  }
  addObservable(e, t) {
    this.clientInterface.observables.hasOwnProperty(e), (this.observables[e] = t)
    const i = this
    return {
      dispose() {
        i.removeObservable(e)
      }
    }
  }
  removeObservable(e) {
    delete this.observables[e]
    for (const t in this.registeredObservers) {
      const i = this.registeredObservers[t],
        n = i[e]
      n && n.cancel(), delete i[e]
    }
  }
  addCollectionToInterface(e, t) {
    const i = this.getInterfaceIndex(e)
    this.addCollection(i, t), (this.clientInterface.collections[i] = Object.assign({}, e))
  }
  addCollection(e, t) {
    this.clientInterface.collections.hasOwnProperty(e), (this.collections[e] = t)
    const i = this
    return {
      dispose() {
        i.removeCollection(e)
      }
    }
  }
  removeCollection(e) {
    delete this.collections[e]
    for (const t in this.registeredCollectionObservers) {
      const i = this.registeredCollectionObservers[t],
        n = i[e]
      n && n.cancel(), delete i[e]
    }
  }
  getInterfaceIndex(e) {
    let t = `${e.name}`
    return e.namespace && (t = `${e.namespace}.${t}`), t
  }
  broadcast(e, t, i, n = !0) {
    const s = this.registeredEventUsers[e] > 0
    if (n || s)
      if (t)
        if (void 0 !== i) {
          const s = t(i)
          this.postMessageHost.broadcastEvent(e, s, n), this.directMessageHost.broadcastEvent(e, s, n)
        } else {
          const i = t()
          this.postMessageHost.broadcastEvent(e, i, n), this.directMessageHost.broadcastEvent(e, i, n)
        }
      else this.postMessageHost.broadcastEvent(e, void 0, n), this.directMessageHost.broadcastEvent(e, void 0, n)
  }
  notifyObservableUpdate(e, t, i) {
    this.postMessageHost.broadcastObservationToClient(e, t, i), this.directMessageHost.broadcastObservationToClient(t, i)
  }
  async onConnectionReceived(e: any) {
    this.applicationKey = this.applicationKey || e.applicationKey || null
    if (!this.clientFilter(e)) return e.reject("Connection refused")
    // try {
    //   await this.verifyConnection(e)
    // } catch (t) {
    //   return e.reject('key/referrer mismatch')
    // }

    const t = async (t?) => {
      var i
      const n = {
        enums: this.clientInterface.enums,
        functions: Object.assign(Object.assign({}, this.clientInterface.functions), this.clientInterface.commands),
        observables: this.clientInterface.observables,
        collections: this.clientInterface.collections
      }
      this.trackSdkConnect(e)
      this.config.onClientConnect(null === (i = e.options) || void 0 === i ? void 0 : i.auth)
      e.accept(await this.getClientScriptUrl(), n, t)
    }
    e.handshake()
    try {
      await this.interfacePromise.then(async () => {
        await t()
      })
    } catch (t) {
      e.reject(t)
    }
  }
  verifyConnection(e) {
    const t = {
      cache: !1
    }
    return this.requestQueue.get(this.validationUrl, t)
  }
  disconnectClient(e) {}
  onActionReceived(e) {
    if (this.tryActionThroughCommand(e)) return
    const t = this.commandCreators[e.targetFunction]
    if (!t) return e.onFail(`${e.targetFunction} is not a valid command`)
    this.trackSdkCall(e)
    try {
      this.issueCommand(t(e.params)).then(e.onSuccess, t => e.onFail(t.message))
    } catch (t) {
      N.debug(t), e.onFail(t["message"])
    }
  }
  tryActionThroughCommand(e) {
    const t = this.commands[e.targetFunction]
    if (!t) return !!this.clientInterface.commands.hasOwnProperty(e.targetFunction) && (e.onFail(`${e.targetFunction} is not ready to be called`), !0)
    this.trackSdkCall(e)
    try {
      t.exec(e.params, new ReturnObserver(e))
    } catch (t) {
      N.debug(t), e.onFail(t["message"])
    }
    return !0
  }
  onSubscribeReceived(e) {
    this.registeredEventUsers.hasOwnProperty(e.subscription) || (this.registeredEventUsers[e.subscription] = 0),
      this.registeredEventUsers[e.subscription]++,
      this.trackSdkEvent(w.SUBSCRIBED, e)
  }
  onUnsubscribeReceived(e) {
    this.registeredEventUsers.hasOwnProperty(e.subscription) && (this.trackSdkEvent(w.UNSUBSCRIBED, e), this.registeredEventUsers[e.subscription]--)
  }
  async onObservableSubReceived(e) {
    const t = e.fromId,
      i = e.observableKey,
      n = this.observables[i]
    if (n) {
      const s = await n
      if (!this.observables[i]) return
      if (((this.registeredObservers[t] = this.registeredObservers[t] || {}), void 0 === this.registeredObservers[t][i])) {
        const n = new SdkObserver()
        ;(this.registeredObservers[t][i] = s.subscribe(n)), this.observerMap.set(n, [t, i, s]), this.trackClientSubscribe(w.OBSERVABLE_SUB, e)
      }
    } else N.error(i, "is not a valid, registered observable")
  }
  onObservableUnsubReceived(e) {
    const t = e.fromId,
      i = e.observableKey
    this.registeredObservers[t] &&
      this.registeredObservers[t][i] &&
      (this.registeredObservers[t][i].cancel(), delete this.registeredObservers[t][i], this.trackClientSubscribe(w.OBSERVABLE_UNSUB, e))
  }
  async onCollectionSubReceived(e) {
    const t = e.fromId,
      i = e.collectionKey,
      n = this.collections[i]
    if (n) {
      const s = await n
      if (!this.collections[i]) return
      ;(this.registeredCollectionObservers[t] = this.registeredCollectionObservers[t] || {}),
        void 0 === this.registeredCollectionObservers[t][i] &&
          ((this.registeredCollectionObservers[t][i] = s.observe({
            onAdded: (e, n) => {
              this.postMessageHost.broadcastCollectionItemAdded(t, i, e, n), this.directMessageHost.broadcastCollectionItemAdded(i, e, n)
            },
            onRemoved: e => {
              this.postMessageHost.broadcastCollectionItemRemoved(t, i, e), this.directMessageHost.broadcastCollectionItemRemoved(i, e)
            },
            onUpdated: (e, n) => {
              this.postMessageHost.broadcastCollectionItemUpdated(t, i, e, n), this.directMessageHost.broadcastCollectionItemUpdated(i, e, n)
            },
            onCollectionUpdated: () => {
              this.postMessageHost.broadcastCollectionUpdated(t, i), this.directMessageHost.broadcastCollectionUpdated(i)
            }
          })),
          this.trackClientSubCollection(w.COLLECTION_SUB, e))
    } else N.error(i, "is not a valid, registered collection")
  }
  onCollectionUnsubReceived(e) {
    const { fromId: t, collectionKey: i } = e
    this.registeredCollectionObservers[t] &&
      this.registeredCollectionObservers[t][i] &&
      (this.registeredCollectionObservers[t][i].cancel(), delete this.registeredCollectionObservers[t][i], this.trackClientSubCollection(w.COLLECTION_UNSUB, e))
  }
  trackSdkEvent(e, t) {
    if (!this.analytics) return
    const i = e === w.SUBSCRIBED ? "on" : "off",
      n = this.valueToClientInterface[t.subscription]
    if (!n) return
    const s = Object.keys(n.values),
      r = s.find((e, i) => {
        const r = s[i]
        return n.values[r] === t.subscription
      })
    if (!r) return
    const o = {
      origin: t.origin,
      applicationKey: this.applicationKey,
      name: i,
      namespace: n.namespace,
      eventType: r,
      count: this.registeredEventUsers[t.subscription],
      method: t.method
    }
    this.analytics.track("sdk_event", t.subscription, o)
  }
  trackSdkConnect(e) {
    if (!this.analytics) return
    const t = {
      origin: e.origin,
      applicationKey: this.applicationKey,
      method: e.method
    }
    this.analytics.track("sdk_connect", "connect", t)
  }
  trackSdkCall(e) {
    if (!this.analytics) return
    const t = this.clientInterface.functions[e.targetFunction] || this.clientInterface.commands[e.targetFunction],
      i = Object.assign(Object.assign({ origin: e.origin, applicationKey: this.applicationKey }, t), {
        method: e.method
      })
    this.analytics.track("sdk_call", e.targetFunction, i)
  }
  trackClientSubscribe(e, t) {
    const i = e === w.OBSERVABLE_SUB,
      n = this.clientInterface.observables[t.observableKey],
      s = Object.assign(Object.assign({ origin: t.origin, applicationKey: this.applicationKey }, n), {
        is_collection: !1,
        action: i ? "subscribe" : "cancel",
        method: t.method
      })
    this.analytics.track("sdk_subscribe", t.observableKey, s)
  }
  trackClientSubCollection(e, t) {
    const i = e === w.COLLECTION_SUB,
      n = this.clientInterface.collections[t.collectionKey],
      s = Object.assign(Object.assign({ origin: t.origin, applicationKey: this.applicationKey }, n), {
        is_collection: !0,
        action: i ? "subscribe" : "cancel",
        method: t.method
      })
    this.analytics.track("sdk_subscribe", t.collectionKey, s)
  }
}
class ReturnObserver {
  action: any
  constructor(e) {
    this.action = e
  }
  return(e) {
    this.action.onSuccess(e)
  }
  throw(e) {
    this.action.onFail(e)
  }
}
// const L = Sdk
// export default {
//   Sdk,
//   default: L
// }
